package com.wanli.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    LoginFailureHandler loginFailureHandler;  //登录验证失败处理器
    @Autowired
    LoginSuccessHandler loginSuccessHandler;
    @Autowired
    CaptchaFilter captchaFilter;   //验证码过滤器
    @Autowired
    UserDetailsServiceImpl userDetailsService;   //注入用户名和密码的那个实现类。
    @Autowired
    AuthenticcationEntryPoint authenticcationEntryPoint;  //jwt验证失败的处理器
    @Autowired
    UserAccessDeniedHandler userAccessDeniedHandler;   //权限不足验证失败的处理器
    @Autowired
    UserLogoutSuccessHandler userLogoutSuccessHandler;

    //配置jwt过滤器，让SpringIOC创建对象
    @Bean
    public JWTAuthenticationFilter jwtAuthenticationFilter() throws Exception{
        return new JWTAuthenticationFilter(authenticationManager());
    }

    @Bean
    public BCryptPasswordEncoder cryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //SpringSecurity安全验证，并不是所有的路径都要身份权限验证。
    //定义路径白名单
    public static final String[] URL_WHITELIST={
        "/api/captcha", "/login", "/logout"
    };

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
        .formLogin()   //启动Vue登录界面，不再使用SpringSecurity
        .failureHandler(loginFailureHandler)   //配置登录失败的处理器
        .successHandler(loginSuccessHandler)  //登录成功的处理器

        .and()
        .logout() //配置登出操作的处理器
        .logoutSuccessHandler(userLogoutSuccessHandler)

        /*springSecurity拦截规则
        authorizeRequests() : 对所有的请求URL进行springSecurity验证
        antMatchers() 设置请求放行的负责，采用白名单放行规则
        permitAll()  对所有人都采用这个规则
        anyRequest()  表示匹配任意请求URL请求
        authenticated()  任意请求都必须被 springSecurity 验证之后才能访问
        */
        .and()
        .authorizeRequests()
        .antMatchers(URL_WHITELIST).permitAll()
        .anyRequest().authenticated()

         /* 因为项目采用前后分离开发，不使用session，所以禁用session
            sessionManagement().sessionCreationPolicy()设置session状态
            SessionCreationPolicy.STATELESS springSecurity永远不会使用session
            SessionCreationPolicy.ALWAYS  总是创建session
            SessionCreationPolicy.NEVER  不会创建session，但是如果session已经存在，是可以使用session的
            SessionCreationPolicy.IF_REQUIRED springSecurity只会在需要时创建一个session
         */

        .and()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        //配置异常处理器
        .and()
        .exceptionHandling()
        .accessDeniedHandler(userAccessDeniedHandler) //权限不足的处理器
        .authenticationEntryPoint(authenticcationEntryPoint)  //Jwt验证失败的处理器

        //登录验证码校验过滤器
        .and()
        .addFilter(jwtAuthenticationFilter())//验证jwt过滤器
        .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);
    }
}
